#pragma once
#include "Sock.hpp"
#include "log.hpp"
#include <poll.h>
#define FD_NONE -1
static const uint16_t g_port = 8080;
const int nfds = 64;
class pollServer
{
public:
    pollServer(uint16_t port = g_port) : _port(port), _nfds(nfds)
    {
        _listensock = Sock::Socket();
        Sock::Bind(_listensock, _port);
        Sock::Listen(_listensock);
        logMessage(DEBUG, "creat base socket success");
        _pfd_arr = new struct pollfd[nfds];

        for (int i = 0; i < _nfds; i++)
        {
            _pfd_arr[i].fd = FD_NONE;
            _pfd_arr[i].events = _pfd_arr[i].revents = 0;
        }
        _pfd_arr[0].fd = _listensock;
        _pfd_arr[0].events = POLLIN;
        _timeout = -1;
    }
    void start()
    {
        while (true)
        {
            // DebugPrint();
            int ret = poll(_pfd_arr, _nfds, _timeout);
            switch (ret)
            {
            case 0:
                logMessage(DEBUG, "time out....");
                break;
            case -1:
                logMessage(WARNING, "select error: %d : %s", errno, strerror(errno));
                break;
            default:
                handlerEvent();
                break;
            }
        }
    }

    ~pollServer()
    {
        if (_listensock > 0)
            close(_listensock);
    }

private:
    void handlerEvent()
    {
        for (int i = 0; i < _nfds; i++)
        {
            if (_pfd_arr[i].fd == FD_NONE)
                continue;
            if (_pfd_arr[i].revents & POLLIN)
            {
                if (_pfd_arr[i].fd == _listensock)
                {
                    Accepter();
                }
                else
                {
                    Recver(i);
                }
            }
        }
    }
    void Accepter()
    {
        std::string clientip;
        uint16_t clientport;
        int sock = Sock::Accept(_listensock, &clientip, &clientport);
        if (sock < 0)
        {
            logMessage(WARNING, "accept error");
            return;
        }
        logMessage(DEBUG, "get a new line success : [%s:%d] : %d", clientip.c_str(), clientport, sock);
        int pos = 1;
        for (; pos < _nfds; pos++)
        {
            if (_pfd_arr[pos].fd == FD_NONE)
                break;
        }
        if (pos == _nfds)
        {
            logMessage(WARNING, "_pfd_arr full,close sock");
            close(sock);
        }
        _pfd_arr[pos].fd = sock;
        _pfd_arr[pos].events = POLLIN;
    }
    void Recver(int pos)
    {
        char buffer[1024];
        ssize_t n = recv(_pfd_arr[pos].fd, buffer, sizeof(buffer) - 1, 0);
        if (n < 0)
        {
            logMessage(WARNING, "recv error");
            close(_pfd_arr[pos].fd);
            _pfd_arr[pos].fd = FD_NONE;
            _pfd_arr[pos].events = _pfd_arr[pos].events = 0;
            return;
        }
        else if (n == 0)
        {
            logMessage(DEBUG, "clientsock close,me too");
            close(_pfd_arr[pos].fd);
            _pfd_arr[pos].fd = FD_NONE;
            _pfd_arr[pos].events = _pfd_arr[pos].events = 0;
        }
        else
        {
            buffer[n] = 0;
            logMessage(DEBUG, "client[%d]# %s", _pfd_arr[pos].fd, buffer);
        }
    }
    void DebugPrint()
    {
        std::cout << "_fd_array[]: ";
        for (int i = 0; i < _nfds; i++)
        {
            if (_pfd_arr[i].fd == FD_NONE)
                continue;
            std::cout << _pfd_arr[i].fd << " ";
        }
        std::cout << std::endl;
    }

private:
    int _listensock;
    uint16_t _port;
    struct pollfd *_pfd_arr;
    int _nfds;
    int _timeout;
};